package com.itheima.redbaby.dao.base;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.itheima.redbaby.GloableParams;
import com.itheima.redbaby.dao.DBHelper;
import com.itheima.redbaby.dao.annotation.Column;
import com.itheima.redbaby.dao.annotation.Id;
import com.itheima.redbaby.dao.annotation.TableName;



public class DaoImpl<T> implements Dao<T>{
	private SQLiteDatabase db;
	private Context context;
	private DBHelper helper;

	public DaoImpl() {
		super();
		this.context = GloableParams.context;
		helper = new DBHelper(context);
		db = helper.getWritableDatabase();
	}
	
	@Override
	public long insert(T t) {
		ContentValues values = fillContentValues(t);
		long l = db.insert(getTable(), null, values);
		return l;
	}

	@Override
	public int delete(Serializable priKey) {
		PriKey key = getPrimaryKey(getInstance());
		int i = db.delete(getTable(), key.key + "=?", new String[]{priKey + ""});
		return i;
	}
	@Override
	public int delete() {
		int i=db.delete(getTable(), null, null);
		return i;
	}
	@Override
	public int update(T t) {
		ContentValues values = fillContentValues(t);
		PriKey key = getPrimaryKey(t);
		db.update(getTable(), values, key.key + "=?", new String[]{key.value});
		return 0;
	}

	@Override
	public List<T> findAll() {
		Cursor cursor = db.query(getTable(), null, null, null, null, null, null);
		List<T> list = new ArrayList<T>();
		while(cursor.moveToNext()) {
			T t = getInstance();
			fillBean(t, cursor);
			list.add(t);
		}
		return list;
	}
	
	private String getTable() {
		T t = getInstance();
		TableName anno = t.getClass().getAnnotation(TableName.class);
		if(anno != null) {
			return anno.value();
		}
		return null;
	}

	/**
	 * Insert a JavaBean to a ContentValues.
	 * @param t
	 * @return
	 */
	private ContentValues fillContentValues(T t) {
		ContentValues values = new ContentValues();
		Field[] fields = t.getClass().getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			Column col = field.getAnnotation(Column.class);
			if(col != null) {
				//假如是主键并且自增
				Id priKey = field.getAnnotation(Id.class);
				if(priKey != null && priKey.autoincrement())
					continue;
				String key = col.key();
				try {
					Object va = field.get(t);
					if(va != null) {
						String value = va.toString(); 
						values.put(key, value);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return values;
	}

	/**
	 * Fill a cursor to a JavaBean, be attention to set a proper position to the cursor.
	 * @param t
	 * @param cursor
	 */
	private void fillBean(T t, Cursor cursor) {
		Field[] fields = t.getClass().getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			Column col = field.getAnnotation(Column.class);
			if(col != null) {
				int index = cursor.getColumnIndex(col.key());
				String val = cursor.getString(index);
				try {
					//val是String类型，假如field为int或long类型，则set()方法执行会出错，所以要判断
					if (field.getType() == int.class) {
						field.set(t, Integer.parseInt(val));
					} else if (field.getType() == long.class) {
						field.set(t, Long.parseLong(val));
					} else if (field.getType() == float.class) {
						field.set(t, Float.parseFloat(val));
					} else {
						field.set(t, val);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * Get a T instance with default empty construct.
	 * @return T instance
	 */
	private T getInstance() {
		Type superclass = this.getClass().getGenericSuperclass();
		if(superclass instanceof ParameterizedType) {
			ParameterizedType paraType = ((ParameterizedType) superclass);
			Class instanceType = (Class) paraType.getActualTypeArguments()[0];
			try {
				return (T) instanceType.newInstance();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}
	
	private PriKey getPrimaryKey(T t) {
		PriKey priKey = new PriKey();
		Field[] fields = t.getClass().getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			Id pKey = field.getAnnotation(Id.class);
			if(pKey != null) {
				Column column = field.getAnnotation(Column.class);
				priKey.key = column.key();
				try {
					priKey.value = field.get(t).toString();
				} catch (Exception e) {
					e.printStackTrace();
				}
				priKey.autoincrement = pKey.autoincrement();
				return priKey;
			}
		}
		return null;
	}
	
	class PriKey {
		/**
		 * 主键的列名
		 */
		String key;
		/**
		 * 主键的值
		 */
		String value;
		/**
		 * 主键是否自增
		 */
		boolean autoincrement;
	}

	
}
